package org.groupg.practice.data.master;

import java.io.ByteArrayOutputStream;
import java.util.zip.Deflater;
import java.util.zip.Inflater;

/**
 * 列式存储 + ZLIB压缩
 * 适合冷数据或归档数据
 */
public class CompressedColumnarStore {
    private final int recordCount;
    private byte[] compressedIds;
    private byte[] compressedTimestamps;
    private byte[] compressedValues;
    private byte[] compressedLabels;

    public CompressedColumnarStore(int[] ids, long[] timestamps,
                                 double[] values, String[] labels) {
        this.recordCount = ids.length;
        compressData(ids, timestamps, values, labels);
    }

    private void compressData(int[] ids, long[] timestamps,
                            double[] values, String[] labels) {
        try {
            // 压缩ID数组
            ByteArrayOutputStream idBytes = new ByteArrayOutputStream();
            for (int id : ids) {
                idBytes.write((id >> 24) & 0xFF);
                idBytes.write((id >> 16) & 0xFF);
                idBytes.write((id >> 8) & 0xFF);
                idBytes.write(id & 0xFF);
            }
            compressedIds = compress(idBytes.toByteArray());

            // 压缩时间戳数组
            ByteArrayOutputStream tsBytes = new ByteArrayOutputStream();
            for (long ts : timestamps) {
                for (int i = 56; i >= 0; i -= 8) {
                    tsBytes.write((int) ((ts >> i) & 0xFF));
                }
            }
            compressedTimestamps = compress(tsBytes.toByteArray());

            System.out.printf("压缩率: IDs %.1f%%, Timestamps %.1f%%%n",
                (1 - compressedIds.length / (double)(ids.length * 4)) * 100,
                (1 - compressedTimestamps.length / (double)(timestamps.length * 8)) * 100);

        } catch (Exception e) {
            throw new RuntimeException("压缩失败", e);
        }
    }

    private byte[] compress(byte[] data) {
        Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION);
        deflater.setInput(data);
        deflater.finish();

        ByteArrayOutputStream output = new ByteArrayOutputStream(data.length);
        byte[] buffer = new byte[1024];
        while (!deflater.finished()) {
            int count = deflater.deflate(buffer);
            output.write(buffer, 0, count);
        }
        return output.toByteArray();
    }

    public long getMemoryUsage() {
        return (compressedIds != null ? compressedIds.length : 0) +
               (compressedTimestamps != null ? compressedTimestamps.length : 0) +
               (compressedValues != null ? compressedValues.length : 0) +
               (compressedLabels != null ? compressedLabels.length : 0);
    }
}